/*=========================================================================

Program:   Virtual Surgery
Language:  C++
Date:      2009-9-1
Version:   0.1
Mail:		   nelfylee@gmail.com

Copyright (c) 2009 Nelfy Lee. All rights reserved.

=========================================================================*/
#include "PipelineModel.h"
#include "DisplayModel.h"
#include "Source.h"
#include "SurfaceSource.h"

#include <QDebug>
#include <QString>


PipelineModel::PipelineModel(QObject *parent) 
:QAbstractItemModel(parent)
{
	m_rootItem = new QStandardItem("root");
	m_iconVolume = new QIcon(QPixmap(":/res/volumeSource.png"));
	m_iconSurface = new QIcon(QPixmap(":/res/surfaceSource.png"));
	m_iconStarOn = new QIcon(QPixmap(":/res/star_on.png"));
	m_iconStarOff = new QIcon(QPixmap(":/res/star_off.png"));
}


PipelineModel::~PipelineModel()
{
	delete m_rootItem;
}


int PipelineModel::getFreeSubID()
{
	return rowCount()+1;
}


void PipelineModel::addSource(Source *source)
{
	if ( source->parent())
	{
		source->parent()->appendRow(source);
	}
	else
	{
		m_rootItem->appendRow((QStandardItem*)source);
	}

	source->m_pipelineModel = this;
	
	sourceAdded(source);
}


// rewrite this process XXX
void PipelineModel::setBaseSource(const QModelIndex& index)
{
	emit emitSetBase(index);
}


void PipelineModel::removeSource(Source *source)
{
	if ( !source)
		return;

	QModelIndex index = source->index();
	if ( !index.isValid())
		return;

	removeSource(index);
}


// rewrite this function XXX
void PipelineModel::removeSource(const QModelIndex& index)
{
	QStandardItem *item = itemFromIndex(index);
	//Source *source = (Source*)item;
	//source->setVisibility(false);

	emit emitSourcePreRemove(index);

	if ( item->parent() && item->parent()->index().isValid())
		removeRow(item->row(), item->parent()->index());
	else
		removeRow(item->row());
}


void PipelineModel::propertyChanged(Source *source, SourceProperty sp)
{
	if ( !source)
		return;

 	emit emitPropertyChanged(source, sp);
}


Source* PipelineModel::sourceFromIndex(const QModelIndex& index) const
{
	return static_cast<Source*>(itemFromIndex(index));
}


QVariant PipelineModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())
		return QVariant();

	if (role == Qt::DecorationRole) 
	{
		switch ( index.column())
		{
		case 0:
			{
				switch(sourceType(index))
				{
				case stVolume:
					{
						QPixmap pixmap = m_iconVolume->pixmap(QSize(22, 22),
							m_displayModel->isDisplaying2D(index) ? QIcon::Normal : QIcon::Disabled);

						return qVariantFromValue(QIcon(pixmap));
					}
				case stSurface:
					{
						QPixmap pixmap = m_iconSurface->pixmap(QSize(22, 22),
							m_displayModel->isDisplaying2D(index) ? QIcon::Normal : QIcon::Disabled);

						return qVariantFromValue(QIcon(pixmap));
					}
                default:
                        return QVariant();  
				}
			}
		case 1:
			{
				if ( m_displayModel->isDisplayingOutline(index))
					return qVariantFromValue(*m_iconStarOn);
				else
					return qVariantFromValue(*m_iconStarOff);
			}
		case 2:
			{
				if ( m_displayModel->isDisplayingModel(index))
					return qVariantFromValue(*m_iconStarOn);
				else
					return qVariantFromValue(*m_iconStarOff);
			}
// 		case 3:
// 			{
// 				if ( m_displayModel->isDisplayingVolume(index))
// 					return qVariantFromValue(*m_iconStarOn);
// 				else
// 					return qVariantFromValue(*m_iconStarOff);
// 			}
		default:
			return QVariant();
		}
	}

	if ( role == Qt::DisplayRole)
	{
		switch ( index.column())
		{
		case 0:
			{
				QStandardItem *item = itemFromIndex(index);

				return QVariant(item->text());
			}
		case 1:
		case 2:
		case 3:
		default:
			return QVariant();
		}
	}

	return QVariant();
}



QModelIndex PipelineModel::index( int row, int column, const QModelIndex &parent /*= QModelIndex()*/ ) const
{
	if (!hasIndex(row, column, parent))
		return QModelIndex();

	QStandardItem *parentItem;

	if (!parent.isValid())
		parentItem = m_rootItem;
	else
		parentItem = static_cast<QStandardItem*>(parent.internalPointer());

	QStandardItem *childItem = parentItem->child(row);
	if (childItem)
		return createIndex(row, column, childItem);
	else
		return QModelIndex();
}

QModelIndex PipelineModel::parent( const QModelIndex &child ) const
{
	if (!child.isValid())
		return QModelIndex();

	QStandardItem *childItem = static_cast<QStandardItem*>(child.internalPointer());
	QStandardItem *parentItem = childItem->parent();

	if (!parentItem || parentItem == m_rootItem)
		return QModelIndex();

	return createIndex(parentItem->row(), 0, parentItem);
}

QModelIndex PipelineModel::indexFromSource(Source* source) const
{
	QStandardItem *item = static_cast<QStandardItem*>(source);

	return createIndex(0,0,item);
}



Qt::ItemFlags PipelineModel::flags( const QModelIndex &index ) const
{
	if (!index.isValid())
		return 0;

	return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

QVariant PipelineModel::headerData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/ ) const
{
	if (orientation == Qt::Horizontal && role == Qt::DisplayRole) 
	{
		switch (section) 
		{
		case 0:
			return tr("Source");
		case 1:
			return tr("O");
		case 2:
			return tr("D");
		default:
			return QVariant();
		}
	}

	return QVariant();
}

int PipelineModel::rowCount( const QModelIndex &parent /*= QModelIndex()*/ ) const
{
	if (parent.column() > 0)
		return 0;

	QStandardItem *parentItem;

	if (!parent.isValid())
		parentItem = m_rootItem;
	else
		parentItem = static_cast<QStandardItem*>(parent.internalPointer());

	return parentItem->rowCount();
}

int PipelineModel::columnCount( const QModelIndex &parent /*= QModelIndex()*/ ) const
{
	return 3;
}

QStandardItem* PipelineModel::itemFromIndex( const QModelIndex& index) const
{
	return static_cast<QStandardItem*>(index.internalPointer());
}

void PipelineModel::setDisplayModel( DisplayModel* dm)
{
	m_displayModel = dm;
}

void PipelineModel::slotUpdate()
{
	emit layoutChanged();
}

void PipelineModel::sourceAdded( Source* source)
{
	QModelIndex index = createIndex(source->parent()->rowCount(), 0, (QStandardItem*)source);
	if ( index.isValid())
		emit emitSourceAdded(index);

	slotUpdate();
}

void PipelineModel::createSurfaceSource( const QModelIndex& index)
{
	Source *source = sourceFromIndex(index);

	if ( source && source->type() == stVolume)
	{
		SurfaceSource *ssource = new SurfaceSource("Surface");

		vtkImageData *data = vtkImageData::New();
		data->DeepCopy(source->data());
		data->Update();

// 		double range[2];
// 		data->GetScalarRange(range);
// 
// 		vtkContourFilter *contour = vtkContourFilter::New();
// 		contour->SetInput(data);
// 		contour->SetValue(0,(range[0]+range[1])/2.0);
// 		contour->Update();

		ssource->setData(NULL, data);

		source->addChild((Source*)ssource);
	}
}

SourceType PipelineModel::sourceType( const QModelIndex& index) const
{
	Source *source = sourceFromIndex(index);

	if ( source)
		return source->type();
	else
		return stNone;
}



